<template>
	<view class="bluetooth-test">
		<view class="section">
			<text class="title">蓝牙测试工具</text>
			<text>状态: {{ ConnectionState[states.connected] }}</text>
		</view>

		<view class="section">
			<button @click="scanDevices" :disabled="states.connected !== ConnectionState.DISCONNECTED">
				扫描设备
			</button>

			<view v-if="states.devices.length > 0" class="device-list">
				<text>发现设备 ({{ states.devices.length }}):</text>
				<view v-for="device in states.devices" :key="device.deviceId" class="device-item">
					<text>
						{{ device.name || '未知设备' }} ({{ device.deviceId }})
					</text>
					<button size="mini" @click="() => connectDevice(device)"
						:disabled="states.connected !== ConnectionState.DISCONNECTED">
						连接
					</button>
				</view>
			</view>
		</view>
		<button @click="runThousand">重复 100 次读写</button>
		<template v-if="states.connected === ConnectionState.CONNECTED">
			<view class="section">
				<text>已连接设备: {{ states.deviceId }}</text>
				<button @click="cancel">断开连接</button>
			</view>

			<view class="section">
				<view class="button-group">
					<button @click="sendData('read')">
						读取版本信息
					</button>
					<button @click="sendData('write')">写入版本信息</button>
				</view>
			</view>

			<view class="section">
				<text>接收到的数据:</text>
				<view> {{ receivedData || '' }}</view>
			</view>
		</template>

		<view class="section">
			<text>操作日志:</text>
			<scroll-view scroll-y class="log-box">
				<p v-for="(log, i) in logs" :key="i">{{ log }}</p>
			</scroll-view>
		</view>
	</view>
</template>

<script lang="ts">
import Vue from 'vue';
import { remoteBluetooth, ConnectionState, EmitEvent, Operation, Device, RemoteControllerInfoType } from '@/utils';

interface BLEService {
	uuid: string;
	[key: string]: any;
}

interface BLECharacteristic {
	uuid: string;
	[key: string]: any;
}

interface State {
	deviceId: string;
	connected: ConnectionState;
	services: BLEService[];
	characteristics: BLECharacteristic[];
	devices: Device[];
}
const bletv = "62 6c 65 74 76 00 00 00 62 6c 65 31 00 00 00 00 00 00 02 d1 40 61 39 15 00 00 00 00 00 00 00 00 00 00 00 01 62 74 30 31 00 00 00 00 00 00 00 01 00 00 04 78 00 00 00 3c 00 00 02 b5 00 00 00 00 00 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 75 30 00 0a 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 27 10 00 03 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 88 00 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 03 07 00 ba 00 00 00 00 04 07 00 c7 00 00 00 00 13 07 00 bc 00 00 00 00 14 07 00 bd 00 00 00 00 15 07 00 be 00 00 00 00 16 07 00 bf 00 00 00 00 17 07 00 c6 00 00 00 00 18 07 00 dc 00 00 00 00 19 07 00 dd 00 00 00 00 1a 07 00 ab 00 00 00 00 52 07 00 bb 00 00 00 00 a4 07 00 b6 00 00 00 00 b0 07 00 bb 00 00 00 00 b2 07 00 b7 00 00 00 03 f4 07 00 79 00 00 00 04 04 07 00 ba 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1e 00 1a 01 03 f4 02 04 04 03 00 03 04 00 17 05 00 04 06 00 52 07 00 13 08 00 14 09 00 15 0a 00 16 0b 00 b2 0c 00 e7 0d 00 18 0e 00 19 0f 00 a4 10 00 b0 11 00 a6 12 00 a7 13 03 f3 14 00 08 15 00 09 16 00 0a 17 00 0b 18 00 0c 19 00 0d 1a 00 0e 1b 00 0f 1c 00 10 1d 00 07 1e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 16 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
const irtv = "45 54 56 00 00 03 00 00 00 00 00 00 00 00 00 01 00 00 01 4e 32 01 01 01 00 10 00 00 01 02 30 00 00 20 00 01 02 30 02 30 02 30 06 90 00 00 00 00 00 00 00 00 23 28 11 94 00 00 00 00 20 00 01 02 42 9e fc 00 03 00 40 bf 51 ae 00 00 00 00 00 04 00 40 bf 40 bf 00 00 00 00 00 13 00 40 bf 19 e6 00 00 00 00 00 14 00 40 bf 1d e2 00 00 00 00 00 15 00 40 bf 46 b9 00 00 00 00 00 16 00 40 bf 47 b8 00 00 00 00 00 17 00 40 bf 0a f5 00 00 00 00 00 18 00 40 bf 1a e5 00 00 00 00 00 19 00 40 bf 1e e1 00 00 00 00 00 1a 00 40 bf 12 ed 00 00 00 00 00 52 00 40 bf 5b a4 00 00 00 00 00 a4 00 40 bf 10 ef 00 00 00 00 00 b0 00 40 bf 5b a4 00 00 00 00 00 b2 00 40 bf 14 eb 00 00 00 00 03 f4 00 40 bf 21 de 00 00 00 00 04 04 00 40 bf 51 ae 00 00 00 00 1e 01 00 1a 02 03 f4 03 04 04 04 00 03 05 00 17 06 00 04 07 00 52 08 00 13 09 00 14 0a 00 15 0b 00 16 0c 00 b2 0d 00 e7 0e 00 18 0f 00 19 10 00 a4 11 00 b0 12 00 a6 13 00 a7 14 03 f3 15 00 08 16 00 09 17 00 0a 18 00 0b 19 00 0c 1a 00 0d 1b 00 0e 1c 00 0f 1d 00 10 1e 00 07"
const versionInfo = "77 42 00 89 66 77 3a 56 30 32 2e 37 36 00 0a 74 62 69 3a 32 33 30 35 0a 74 6d 69 3a 31 35 31 0a 69 72 74 76 3a 61 6c 70 68 61 2d 76 31 2e 30 2e 33 34 35 0a 62 6c 65 74 76 3a 61 6c 70 68 61 2d 76 31 2e 30 2e 33 31 38 0a 73 74 76 3a 31 0a 63 6c 6f 63 6b 5f 75 70 64 61 74 65 5f 74 69 6d 65 3a 32 30 32 35 2d 30 34 2d 31 39 54 30 37 3a 32 36 3a 32 37 2e 39 30 30 5a 0a 6a 2e 62 70 61 69 72 3a 30 30 0a 6a 2e 5f 64 69 64 3a 30 ";
const serverId = "10111213-1415-1617-1819-1A1B1C1D1931";
const charId = "10111213-1415-1617-1819-1A1B1C1D2B31";
const tvData = [
	{ type: RemoteControllerInfoType.IR_TV, data: irtv },
	{ type: RemoteControllerInfoType.BLE_TV, data: bletv },
	{ type: RemoteControllerInfoType.VERSION, data: versionInfo }
]
const Settings = {
	MTU: 128, // 最大传输单元
}

export default Vue.extend({
	name: 'BluetoothTest',
	data() {
		return {
			logs: [] as string[],
			states: {
				deviceId: '',
				connected: ConnectionState.DISCONNECTED,
				services: [] as BLEService[],
				characteristics: [] as BLECharacteristic[],
				devices: [] as Device[],
			} as State,
			preDeviceId: '',
			receivedData: '',
			ConnectionState,
			Operation,
		};
	},
	mounted() {
		this.init();
	},
	beforeDestroy() {
		this.cancel();
	},
	methods: {
		addLog(log: string) {
			console.log(`${new Date().toLocaleTimeString()}: ${log}`);
			this.logs = [`${new Date().toLocaleTimeString()}: ${log}`, ...this.logs];
		},
		asyncStates() {
			this.states = {
				...this.states,
				...remoteBluetooth.getState(),
			};
		},
		async init() {
			this.addLog('初始化蓝牙适配器...');
			try {
				// 获取当前权限设置
				await requestPermissions();
			} catch (error) {
				console.log('获取权限异常');
				console.log('error', error);
			}
			await remoteBluetooth.init();
			this.addLog('蓝牙适配器初始化成功');
			remoteBluetooth
				.on(EmitEvent.deviceFound, (device: Device) => {
					this.addLog(`发现设备: ${device.name || '未知'} (${device.deviceId})`);
					this.asyncStates();
				})
				.on(EmitEvent.connectionStateChange, ({ deviceId, connected }: { deviceId: string; connected: boolean }) => {
					const status = connected ? '已连接' : '已断开';
					this.addLog(`设备 ${deviceId} ${status}`);
					this.asyncStates();
					if (connected) {
						this.preDeviceId = deviceId;
					}
					if (!connected) {
						remoteBluetooth.disconnectWithUnPair();
					}
				});
		},
		cancel() {
			try {
				remoteBluetooth.disconnectWithUnPair().then(() => {
					this.asyncStates()
				});
			} catch (error) {
				console.log(error)
			}
		},
		scanDevices() {
			this.addLog('开始扫描设备...');
			remoteBluetooth.scanDevices().then(() => {
				this.addLog('扫描完成');
			});
			this.asyncStates();
		},
		showLoadingToast(title: string) {
			uni.showToast({
				title,
				icon: 'loading',
				duration: 20000,
				mask: true
			});
		},
		handleError(error: Error, defaultMessage: string) {
			uni.hideToast();
			uni.showToast({
				title: defaultMessage,
				icon: 'none'
			});
			this.addLog(`${defaultMessage}: ${error.message}`);
			throw error; // 可以选择继续抛出错误或处理
		},
		async connectDevice(device: any) {
			try {
				this.receivedData = "";
				// 1. 连接设备
				this.showLoadingToast('正在连接设备');
				this.addLog(`正在连接 ${device.name || device.deviceId}...`);
				await remoteBluetooth.connect(device.deviceId);
				await remoteBluetooth.discoverServices();
				await remoteBluetooth.discoverCharacteristics(serverId);
				remoteBluetooth.configure(serverId, charId)
				this.asyncStates();
				if (plus.os.name !== 'iOS') {
					this.showLoadingToast('正在设置MTU');
					await remoteBluetooth.setMTU(Settings.MTU);
					this.addLog(`设置MTU成功 ${Settings.MTU}`);
						// 赛科需要2次设置 mtu
					await remoteBluetooth.sleep(500);
					this.addLog(`设置MTU成功 ${Settings.MTU}`);
				}
				this.showLoadingToast('正在启用通知');
				await remoteBluetooth.startNotification();
				this.addLog('启用通知成功');
				this.asyncStates();
			
				uni.hideToast();
				uni.showToast({
					title: '连接并配置成功',
					icon: 'success',
					duration: 1500
				});
				this.addLog(`设备 ${device.name || device.deviceId} 连接并配置成功`);
				this.sendData('read');
			} catch (error) {
				this.handleError(new Error('未知错误'), '操作失败');
			}
		},
		async sendData(type: 'read' | 'write') {
			const _send = async (type: 'read' | 'write') => {
				switch (type) {
					case 'read':
						this.addLog(`启动读`);
						try {
							this.showLoadingToast('正在读取数据');
							const response = await remoteBluetooth.readRemoteControllerVersionInfo();
							this.receivedData = parseDeviceData(response || '');
							uni.showToast({
								title: '读取数据成功',
								icon: 'success',
							});
						} catch (error) {
							uni.showToast({
								title: '读取数据失败',
								icon: 'success',
							});
							console.log('读取数据失败', error);
						}
						break;
					case 'write':
						try {
							this.showLoadingToast('正在写入 irtv 和 bletv');
							await remoteBluetooth.transferBasicInfo(tvData);
							uni.showToast({
								title: 'irtv 和 bletv 写入成功',
								icon: 'success',
							});
						} catch (error) {
							console.log('irtv 和 bletv 写入失败', error);
							uni.showToast({
								title: 'irtv 和 bletv 写入失败',
								icon: 'none',
							});
						}
						break;
					default:
						break;
				}
			}
			try {
				switch (type) {
					case 'read':
						return await _send(type);
					case 'write':
						await _send(type);
						break;
					default:
						break;
				}
			} catch (err) {
				this.addLog(`发送失败: ${(err as Error).message}`);
			}
		},
		async runThousand() {
			const totalCount = 100;
			let successCount = 0;
			let failCount = 0;
			const deviceId = this.preDeviceId;
			async function* generateIterations() {
				for (let i = 0; i < totalCount; i++) {
					yield i;
				}
			}
			for await (const i of generateIterations()) {
				try {
					this.addLog(`进行第 ${i + 1} 次读写`);
					this.addLog('正在写入 irtv 和 bletv');
					await remoteBluetooth.transferBasicInfo(tvData);
					this.addLog('irtv 和 bletv 写入成功');
					this.addLog('正在读取数据');
					await remoteBluetooth.sleep(200);
					const response = await remoteBluetooth.readRemoteControllerVersionInfo();
					this.addLog('读取数据：' + parseDeviceData(response || ''));
					successCount++
				} catch (error) {
					console.error(`Error at iteration ${i + 1}:`, error);
					failCount++;
				}
			}
			this.addLog(`Completed: ${successCount} successes, ${failCount} failures`);
			return 'done';
		}
	},
});

function parseDeviceData(hexStr: string) {
	// 移除所有空格
	const cleanHex = hexStr.replace(/\s/g, '');

	// 将十六进制字符串转换为Uint8Array
	const bytes = new Uint8Array(cleanHex.length / 2);
	for (let i = 0; i < cleanHex.length; i += 2) {
		bytes[i / 2] = parseInt(cleanHex.substr(i, 2), 16);
	}


	const textBytes = bytes.length > 10 ? bytes.slice(4) : bytes;
	const text = Array.from(textBytes)
		.map(byte => String.fromCharCode(byte))
		.join('');

	// 分割并处理每一行
	const result: any = {};
	const lines = text.split('\n').filter(line => line.trim() !== '');

	for (const line of lines) {
		const colonIndex = line.indexOf(':');
		if (colonIndex === -1) continue;

		const key = line.substring(0, colonIndex);
		const value = line.substring(colonIndex + 1);

		// 移除可能的空字符和其他不可见字符
		const cleanValue = value.replace(/\x00/g, '').trim();

		// 尝试转换为数字（如果是纯数字）
		result[key] = isNaN(Number(cleanValue)) ? cleanValue : Number(cleanValue);
	}
	return JSON.stringify(result || '', null, 2); // 格式化为JSON字符串
}

async function requestPermissions() {
	// 判断当前运行平台
	const isAndroid = plus.os.name === 'Android';
	const isIOS = plus.os.name === 'iOS';
	// Android 权限配置
	const androidPermissions = [
		'android.permission.ACCESS_FINE_LOCATION',
		'android.permission.BLUETOOTH',
		'android.permission.BLUETOOTH_ADMIN'
	];
	// Android 12+ 需要额外权限
	if (isAndroid && plus.os.version && Number(plus.os.version) >= 12) {
		androidPermissions.push(
			'android.permission.BLUETOOTH_SCAN',
			'android.permission.BLUETOOTH_CONNECT'
		);
	}
	return new Promise((resolve, reject) => {
		if (isAndroid) {
			// Android 权限请求
			plus.android.requestPermissions(
				androidPermissions,
				(result) => {
					console.log('Android权限请求结果:', result);
					resolve(result);
				},
				(error) => {
					console.error('Android权限请求失败:', error);
					reject(error);
				}
			);
		} else if (isIOS) {
			// iOS 蓝牙权限请求
			const CBManager = (plus.ios as any).import('CBManager');
			const status = CBManager.authorization;
			console.log('当前iOS蓝牙权限状态:', status);
			// iOS 不需要显式请求，但需要检查状态
			if (status === 3) { // CBManagerAuthorizationAllowedAlways
				resolve('granted');
			} else if (status === 2) { // CBManagerAuthorizationDenied
				// 引导用户去设置页开启
				(plus.ios as any).import('UIApplication').sharedApplication()
					.openURL((plus.ios as any).import('NSURL').URLWithString('app-settings:'));
				reject('permission_denied');
			} else {
				// 其他状态视为已请求
				resolve('not_determined');
			}
		} else {
			reject('unsupported_platform');
		}
	});
}

</script>

<style>
.bluetooth-test {
	padding: 20px;
}

.section {
	margin-bottom: 20px;
}

.title {
	font-size: 18px;
	font-weight: bold;
	margin-bottom: 10px;
	display: block;
}

.device-list {
	margin-top: 10px;
}

.device-item {
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin: 5px 0;
	padding: 5px;
	border: 1px solid #eee;
}

.picker {
	padding: 10px;
	border: 1px solid #ccc;
	margin: 5px 0;
}

.button-group {
	display: flex;
	gap: 10px;
}

.log-box {
	height: 200px;
	border: 1px solid #eee;
	padding: 10px;
	overflow-y: auto;
}
</style>
